package cooperate

import (
	"gddgame.cc/galaxy/common/namespaces/cooperate/structure"
	"gddgame.cc/galaxy/utils/serialize"
)

type ScheduleBuilder struct {
	execute *LogicExecute

	info *structure.ScheduleInfo
	//mapNoId string
	//
	//from   *structure.BaseData
	//target *structure.BaseData
	//key    string
	//time   int64
	//logic  structure.ScheduleLogic
	//params structure.ParamSlice
	//delay  int

	//b []byte
}

func (logic *LogicExecute) ScheduleBuilder() *ScheduleBuilder {
	return &ScheduleBuilder{
		execute: logic,
		info:    &structure.ScheduleInfo{},
	}
}

func (builder *ScheduleBuilder) BindInfo(info structure.ScheduleInfo) *ScheduleBuilder {
	builder.info = &info

	return builder
}

func (builder *ScheduleBuilder) BindMapNoId(mapNoId string) *ScheduleBuilder {
	builder.info.MapNoId = mapNoId
	return builder
}

func (builder *ScheduleBuilder) Target(target structure.BaseData) *ScheduleBuilder {
	builder.info.Target = &target
	return builder
}
func (builder *ScheduleBuilder) Key(key string) *ScheduleBuilder {
	builder.info.Key = key
	return builder
}

func (builder *ScheduleBuilder) Data() []byte {
	return builder.info.Data
}
func (builder *ScheduleBuilder) From(from *structure.BaseData) *ScheduleBuilder {
	builder.info.From = from
	return builder
}
func (builder *ScheduleBuilder) Content() *ScheduleContent {
	content := &ScheduleContent{
		From:     builder.info.From,
		Target:   builder.info.Target,
		Schedule: builder.info.Schedule,
		Key:      builder.info.Key,
		Time:     builder.info.Time,
		Content:  builder.info.Data,
		Delay:    builder.info.ScheduleDelay,
	}
	return content
}
func (builder *ScheduleBuilder) Bind(logic structure.ScheduleLogic, b []byte) *ScheduleBuilder {
	builder.info.Data = b
	builder.info.Schedule = logic
	return builder
}
func (builder *ScheduleBuilder) Once(event structure.EventData) *ScheduleBuilder {
	one := &OnceScheduleContent{Event: event}
	builder.info.Schedule = OnceSchedule
	slot := serialize.GetSlot()
	builder.info.Slot = slot
	_ = slot.Set(one)
	builder.info.Data = slot.Bytes()
	return builder
}

func (builder *ScheduleBuilder) Repeat(repeat int64, event structure.EventData, endDelay int64) *ScheduleBuilder {
	re := &RepeatScheduleContent{Event: event, Repeat: repeat, EndTime: endDelay}
	slot := serialize.GetSlot()
	builder.info.Slot = slot
	_ = slot.Set(re)
	builder.info.Data = slot.Bytes()
	builder.info.Schedule = RepeatSchedule
	return builder
}

func (builder *ScheduleBuilder) RepeatEvery(repeat int64, dependKey string, operateBuilder *OperateBuilder, checkBuilder *CheckBuilder, endDelay int64) *ScheduleBuilder {
	re := &RepeatEveryScheduleContent{
		Checks:    checkBuilder.Data(),
		Repeat:    repeat,
		EndTime:   endDelay,
		DependKey: dependKey,
		Operates:  operateBuilder.DataOfUpdate(),
	}
	slot := serialize.GetSlot()
	builder.info.Slot = slot
	_ = slot.Set(re)
	builder.info.Data = slot.Bytes()
	builder.info.Schedule = RepeatEverySchedule
	return builder
}

func (builder *ScheduleBuilder) Move(scheduleContent *MoveScheduleContent) *ScheduleBuilder {
	slot := serialize.GetSlot()
	builder.info.Slot = slot
	_ = slot.Set(scheduleContent)
	builder.info.Data = slot.Bytes()
	builder.info.Schedule = MoveSchedule

	return builder
}

func (builder *ScheduleBuilder) Touch(scheduleContent *TouchScheduleContent) *ScheduleBuilder {
	slot := serialize.GetSlot()
	builder.info.Slot = slot
	_ = slot.Set(scheduleContent)
	builder.info.Data = slot.Bytes()
	builder.info.Schedule = TouchSchedule

	return builder
}

func (builder *ScheduleBuilder) Schedule(time int64, params structure.ParamSlice, delay int) {
	builder.info.Time = builder.execute.FormatTime(time)
	if params != nil {
		builder.info.Params = params
	}
	builder.info.ScheduleDelay = delay
	builder.execute.PushSchedule(builder)
}

func (builder *ScheduleBuilder) executor(conn structure.SafeConn) {
	info := builder.info
	if info.Version > 0 {
		//fmt.Println("builder schedule update", builder.info.Target, builder.info.Time, builder.info.Key, builder.info.Schedule)
		builder.execute.execute.UpdateSchedule(conn, info, info.Time)
	} else {
		builder.execute.execute.PushSchedule(conn, info)
	}

	builder.info.Release()
	builder.info = nil
}

func (logic *LogicExecute) AddOnceSchedule(mapNoId string, content *ScheduleContent, event structure.EventData, params structure.ParamSlice) error {
	builder := logic.ScheduleBuilder()
	builder.BindMapNoId(mapNoId).From(content.From).Target(*content.Target).Once(event).Key(content.Key).Schedule(content.Time, params, 0)
	return nil
}

func (logic *LogicExecute) AddRepeatSchedule(mapNoId string, content *ScheduleContent, event structure.EventData, repeat int, endTime int) error {
	builder := logic.ScheduleBuilder()
	builder.BindMapNoId(mapNoId).From(content.From).Target(*content.Target).Repeat(int64(repeat), event, logic.FormatTime(int64(endTime))).Key(content.Key).Schedule(content.Time, nil, 0)
	return nil
}

func (logic *LogicExecute) AddTouchSchedule(mapNoId string, content *ScheduleContent, times int, position []byte, t LogicType, logicInfo serialize.IStruct, params structure.ParamSlice) error {
	bb, err := logicInfo.MarshalMsg(nil)
	if err != nil {
		return err
	}
	touch := &TouchScheduleContent{Times: times, Position: position, Type: t, Logic: bb}

	builder := logic.ScheduleBuilder()
	builder.BindMapNoId(mapNoId).From(content.From).Target(*content.Target).Touch(touch).Key(content.Key).Schedule(content.Time, nil, 0)
	return nil
}
